package cn.jasonone.jasonfx.proxy;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import cn.jasonone.jasonfx.entity.JFXBaseController;
import cn.jasonone.jasonfx.entity.Optional;
import cn.jasonone.jasonfx.exception.NotFoundInterceptorException;
import cn.jasonone.jasonfx.interceptor.ControllerInterceptor;
import cn.jasonone.jasonfx.interceptor.InterceptorChain;
import cn.jasonone.jasonfx.util.ClassUtil;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

/**
 * 控制器代理处理器
 * 
 * @author Jason
 * @date: 2020-01-23 17:19
 */
@Data
@NoArgsConstructor
public class Proxy<T> implements MethodInterceptor {
	private T sourceObject, proxy;

	/**
	 * 存储全局拦截器
	 */
	private static final String ANY_CONTROLLER = "ANY_CONTROLLER";

	/**
	 * 控制器调用链
	 */
	private static final Map<String, List<InterceptorChain>> CHAINS = new HashMap<>();

	static {
		// 初始化全局拦截器容器
		CHAINS.put(ANY_CONTROLLER, new ArrayList<>());
	}

	/**
	 * 注册控制器拦截器
	 * 
	 * @param proxy       拦截哪个代理对象,如果为null,则拦截所有代理对象
	 * @param interceptor 拦截器
	 */
	public static void registerInterceptor(Object proxy, ControllerInterceptor interceptor) {
		try {
			if (interceptor == null)
				return;
			Class<? extends ControllerInterceptor> preInterceptor = interceptor.preInterceptor();
			String controllerName = ANY_CONTROLLER;
			if (proxy != null) {
				controllerName = ClassUtil.getClass(proxy.getClass()).getName();
			}
			if (!CHAINS.containsKey(controllerName)) {
				CHAINS.put(controllerName, new ArrayList<>());
			}
			if (preInterceptor == null) {
				CHAINS.get(controllerName).add(new InterceptorChain(interceptor, null));
			} else {
				boolean flag = false;
				for (InterceptorChain interceptorChain : CHAINS.get(controllerName)) {
					if (interceptorChain.append(interceptor)) {
						// 追加成功
						flag = true;
						break;
					}
				}
				if (!flag) {
					// 追加失败
					throw new NotFoundInterceptorException("未找到拦截器:" + preInterceptor);
				}
			}
		} catch (Throwable e) {
			e.printStackTrace();
		}
	}

	@Override
	public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
		Optional<Object> returnValue = new Optional<>();
		for (InterceptorChain chain : CHAINS.get(ANY_CONTROLLER)) {
			chain.intercept(obj, methodProxy, args, returnValue);
		}
		if (CHAINS.containsKey(sourceObject.getClass().getName())) {
			for (InterceptorChain chain : CHAINS.get(sourceObject.getClass().getName())) {
				chain.intercept(obj, methodProxy, args, returnValue);
			}
		}
		if (!returnValue.isChange()) {
			returnValue.set(methodProxy.invokeSuper(obj, args));
		}
		return returnValue.get();
	}

	/**
	 * 创建代理
	 * 
	 * @return 代理对象
	 */
	public T create() {
		if (proxy == null) {
			Enhancer enhancer = new Enhancer();
			enhancer.setSuperclass(sourceObject.getClass());
			enhancer.setCallback(this);
			proxy = (T) enhancer.create();
			ClassUtil.copyFieldValues(sourceObject, proxy);
		}
		return proxy;
	}

	public Proxy(T sourceObject) {
		super();
		this.sourceObject = sourceObject;
	}

}
